package org.it5.Control;

import java.sql.*;
import java.util.Vector;

public class AgentMySQL implements InterfaceAgent {
	//instancia del agente
    protected static AgentMySQL mInstancia=null;
    //Conexion con la base de datos
    protected static Connection mBD;
	//Identificador ODBC de la base de datos
    private static String url="jdbc:mysql://127.0.0.1:3306/mydb";
    // usuario de la BD
    private static String user="navweb";
    // contraseña de la BD
    private static String pass="navweb";
    //Driven para conectar con bases de datos
    private static String driver="com.mysql.jdbc.Driver";
    
    //Constructor
    private AgentMySQL() throws Exception {
    	conectar();
    }
    
    //Implementacion del patron singleton
    //Este patron de diseño permite implementar clases de las cuales
    //solo existir una instancia
    //http://es.wikipedia.org/wiki/Singleton
     public static AgentMySQL getAgente() {
    	try { 
	        if (mInstancia==null){
	          mInstancia=new AgentMySQL();
	        }
	          
	        return mInstancia;
    	} catch( Exception e ) {
    		int n = 10;
    	}
    	
    	return null;
     }
 
    //Metodo para realizar la conexion a la base de datos 
    private void conectar() throws Exception {
         Class.forName(driver);
         mBD=DriverManager.getConnection( this.url, this.user, this.pass);
    }

    
    //Metodo para desconectar de la base de datos
    public void desconectar() throws Exception{
    	mBD.close();
    }

	public Vector<Vector<Object>> read(String SQL) throws SQLException,Exception{
		/*
		 * Metodo para realizar una busqueda o seleccion de informacion enla
		 * base de datos El método select develve un vector de vectores, donde
		 * cada uno de los vectores que contiene el vector principal representa
		 * los registros que se recuperan de la base de datos.
		 */

		// preparamos las variables
		Vector<Vector<Object>> result = new Vector<Vector<Object>>();

		conectar();
		PreparedStatement stmt = mBD.prepareStatement(SQL);
		ResultSet resultado = stmt.executeQuery();

		// obtenemos el numero de columnas que tengamos
		ResultSetMetaData metaData = resultado.getMetaData();
		int nColumn = metaData.getColumnCount();

		while (resultado.next()) {
			// creamos un nuevo vector de columnas
			Vector<Object> vectHorizontal = new Vector<Object>(); 

			// obtenemos las columnas
			for (int i = 1; i <= nColumn; i++)
				vectHorizontal.add(resultado.getObject(i));

			result.add(vectHorizontal);
		}
		
		stmt.close();
		desconectar();
		return result;
	}
	

	public Vector<Vector<Object>> read(String SQL, Vector<DBResource> resources, Vector<DBResource> resourcesOut) throws SQLException,Exception{
		/*
		 * Metodo para realizar una busqueda o seleccion de informacion enla
		 * base de datos El método select develve un vector de vectores, donde
		 * cada uno de los vectores que contiene el vector principal representa
		 * los registros que se recuperan de la base de datos.
		 */

		// preparamos las variables
		Vector<Vector<Object>> result = new Vector<Vector<Object>>();
		int i;

		conectar();
		PreparedStatement stmt = mBD.prepareStatement(SQL);
		
    	i = 1;
    	for ( DBResource dbr : resources ) {
    		switch ( dbr.getType() ) {
				/*case BLOB:
				    Blob blob = mBD.createBlob();
				    InterfaceBlob blobObject = (InterfaceBlob) dbr.getValue();
				    
				    blobObject.getBlob( blob );
				    
				    stmt.setBlob( i, blob );
					break;*/
	
				case DATE:
					java.util.Date utilDate = (java.util.Date) dbr.getValue();
					java.sql.Date sqlDate = new java.sql.Date( utilDate.getTime() );
					
				    stmt.setDate(i, sqlDate );
					break;
					
				case BOOLEAN:
					stmt.setBoolean( i , (Boolean) dbr.getValue() ); 				
					break;
					
				default:
				    stmt.setObject(i, dbr.getValue());
					break;
			}
    		
    		i++;
    	}
    	
		ResultSet resultado = stmt.executeQuery();

		while (resultado.next()) {
			// creamos un nuevo vector de columnas
			Vector<Object> vectHorizontal = new Vector<Object>(); 

			Object o = null;
			// obtenemos las columnas
	    	i = 1;
	    	for ( DBResource dbr : resourcesOut ) {
	    		switch ( dbr.getType() ) {
					case BLOB:
						o = resultado.getBlob( i );
						break;
						
					case DATE:
						java.sql.Date sqlDate = resultado.getDate( i );
						o = new java.util.Date( sqlDate.getTime() );
						
						break;
						
					case BOOLEAN:
						o = resultado.getBoolean( i );					
						break;
						
					default:
						o = resultado.getObject( i );
						break;
				}

	    		vectHorizontal.add( o );
	    		
	    		i++;
	    	}

			result.add(vectHorizontal);
		}
		
		stmt.close();
		desconectar();
		return result;
	}
    
    //Metodo para realizar una modificacion en la base de datos
    public int modify(String SQL) throws SQLException, Exception{ 
     	conectar();
     	
    	PreparedStatement stmt = mBD.prepareStatement(SQL);
    	int res=stmt.executeUpdate();
    	
    	stmt.close();
    	desconectar();
    	return res;
    }
    
    //Metodo para realizar una insercion en la base de datos
    public int modify(String SQL, Vector<DBResource> resources) throws SQLException, Exception{ 
     	conectar();
     	
    	PreparedStatement stmt = mBD.prepareStatement(SQL);
    	
    	int i = 1;
    	for ( DBResource dbr : resources ) {
    		switch ( dbr.getType() ) {
			/*case BLOB:
			    Blob blob = mBD.createBlob();
			    InterfaceBlob blobObject = (InterfaceBlob) dbr.getValue();
			    
			    blobObject.getBlob( blob );
			    
			    stmt.setBlob( i, blob );
				break;*/

			case DATE:
				java.util.Date utilDate = (java.util.Date) dbr.getValue();
				java.sql.Date sqlDate = new java.sql.Date( utilDate.getTime() );
				
			    stmt.setDate(i, sqlDate );
				break;
				
			case BOOLEAN:
				stmt.setBoolean( i , (Boolean) dbr.getValue() ); // !Comprobar			
				break;
				
			default:
			    stmt.setObject(i, dbr.getValue());
				break;
			}
    		
    		i++;
    	}
    	
    	int res=stmt.executeUpdate();    	
    	
    	stmt.close();
    	desconectar();
    	return res;
    }
    
    //Metodo para realizar una insercion en la base de datos
    public int modifyWithID(String SQL) throws SQLException, Exception{ 
     	conectar();
     	
    	PreparedStatement stmt = mBD.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
    	
    	int res=stmt.executeUpdate();    
    	
        if (res == 0) {
        	throw new SQLException("No value inserted.");
        }
        
        int id = -1;
        try {
        	ResultSet generatedKeys = stmt.getGeneratedKeys();
            if (generatedKeys.next()) {
                id = (int) generatedKeys.getLong(1);
            }
            else {
                throw new SQLException("No ID obtained.");
            }
        } catch ( Exception e ) {
        	
        }
    	
    	stmt.close();
    	desconectar();
    	return id;
    }
    
    //Metodo para realizar una insercion en la base de datos
    public int modifyWithID(String SQL, Vector<DBResource> resources) throws SQLException, Exception{ 
     	conectar();
     	
    	PreparedStatement stmt = mBD.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
    	
    	int i = 1;
    	for ( DBResource dbr : resources ) {
    		switch ( dbr.getType() ) {
			/*case BLOB:
			    Blob blob = mBD.createBlob();
			    InterfaceBlob blobObject = (InterfaceBlob) dbr.getValue();
			    
			    blobObject.getBlob( blob );
			    
			    stmt.setBlob( i, blob );
				break;*/

			case DATE:
				java.util.Date utilDate = (java.util.Date) dbr.getValue();
				java.sql.Date sqlDate = new java.sql.Date( utilDate.getTime() );
				
			    stmt.setDate(i, sqlDate );
				break;
				
			case BOOLEAN:
				stmt.setBoolean( i , (Boolean) dbr.getValue() ); 				
				break;
				
			default:
			    stmt.setObject(i, dbr.getValue());
				break;
			}
    		
    		i++;
    	}
    	
    	int res=stmt.executeUpdate();    
    	
        if (res == 0) {
        	throw new SQLException("No value inserted.");
        }
        
        int id = -1;
        try {
        	ResultSet generatedKeys = stmt.getGeneratedKeys();
            if (generatedKeys.next()) {
                id = (int) generatedKeys.getLong(1);
            }
            else {
                throw new SQLException("No ID obtained.");
            }
        } catch ( Exception e ) {
        	
        }
    	
    	stmt.close();
    	desconectar();
    	return id;
    }
}